/*-------------------------------------------------------------------------
 * Filename:      serial.c
 * Version:       $Id: ftuart.c,v 1.1 2008/03/17 08:02:32 zhulin Exp $
 * Copyright:     Copyright (C) 1999, Erik Mouw
 * Author:        Erik Mouw <J.A.K.Mouw@its.tudelft.nl>
 * Description:   Serial utilities for blob
 * Created at:    Tue Aug 24 20:25:00 1999
 * Modified by:   Erik Mouw <J.A.K.Mouw@its.tudelft.nl>
 * Modified at:   Mon Oct  4 20:11:14 1999
 *-----------------------------------------------------------------------*/
/*
 * serial.c: Serial utilities for blob
 *
 * Copyright (C) 1999  Erik Mouw (J.A.K.Mouw@its.tudelft.nl)
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */


#include "config.h"
#include "bulverde.h"
#include "time.h"
#include "ftuart.h"
#include "udelay.h"
/* number of nibbles in a word */
#define NIBBLES_PER_WORD (8)

/*
 * Initialise the serial port with the given baudrate. The settings
 * are always 8 data bits, no parity, 1 stop bit, no start bits.
 *
 */
void ftuart_init(eBauds baudrate)
{
	//int value;

	__REG(CLK_BASE_PHYSICAL+CKEN_OFFSET) |= CKEN6_FFUART;
	//clear
	FFIER = 0;
	FFFCR = 0;
	FFLCR = 0;
	FFMCR = 0;
	FFISR = 0;

	FFFCR = 0X07;	 /* enable FIFO,clear Rx FIFO and Tx FIFO */
  	/* set baud rate */
   	FFLCR = LCR_WLS0 | LCR_WLS1 | LCR_DLAB;
	FFDLL = baudrate & 0xff;
	FFDLH = baudrate >> 8;

	FFLCR = LCR_WLS0 | LCR_WLS1;
  	FFIER = IER_UUE;	 /* Enable BTUART */
  	FFMCR = MCR_RTS; 	/* Auto-RTS Enable*/

}


/*
 * Output a single byte to the BT-serial port.
 */
void ftuart_output_byte(const char c)
{

  /* wait for room in the tx FIFO on BTUART */
  while(( __REG(FFUART_BASE_PHYSICAL+FF_LSR_OFFSET) & LSR_TEMT) == 0);
  __REG(FFUART_BASE_PHYSICAL+FF_THR_OFFSET) = c;
}


/*
 * Output a single byte to the BT-serial port.
 */
void ftuart_output_rawbyte(const char c)
{
  /* wait for room in the tx FIFO on BTUART */
  while(( __REG(FFUART_BASE_PHYSICAL+FF_LSR_OFFSET) & LSR_TEMT) == 0) ;
  __REG(FFUART_BASE_PHYSICAL+FF_THR_OFFSET) = c;

}

extern void buart_output_byte(const char c);
void ftuart_output_byteinhex(const char c)
{
  char d;

  d = (char)((c >> 4) & 0x0f);
  if(d > 9)
    d += ('A' - 10);
  else
    d += '0';
  buart_output_byte(d);

  d = (char)(c & 0x0f);
  if(d > 9)
    d += ('A' - 10);
  else
    d += '0';
  ftuart_output_byte(d);
}


/*
 * Write a null terminated string to the serial port.
 */
void ftuart_output_string(const char *s)
{
	while(*s != 0) {
		ftuart_output_byte(*s++);
	}
}


/*
 * Write the argument of the function in hexadecimal to the serial
 * port. If you want "0x" in front of it, you'll have to add it
 * yourself.
 */
void ftuart_output_hex(const u32 h)
{
	char c;
	int i;

	for(i = NIBBLES_PER_WORD - 1; i >= 0; i--) {
		c = (char)((h >> (i * 4)) & 0x0f);

		if(c > 9)
			c += ('A' - 10);
		else
			c += '0';

		ftuart_output_byte(c);
	}
}


/*
 * Write the argument of the function in decimal to the serial port.
 * We just assume that each argument is positive (i.e. unsigned).
 */
void ftuart_output_dec(const u32 d)
{
	int leading_zero = 1;
	u32 divisor, result, remainder;

	remainder = d;

	for(divisor = 1000000000;
	    divisor > 0;
	    divisor /= 10) {
		result = remainder / divisor;
		remainder %= divisor;

		if(result != 0 || divisor == 1)
			leading_zero = 0;

		if(leading_zero == 0)
			ftuart_output_byte((char)(result) + '0');
	}
}


/*
 * Write a block of data to the serial port. Similar to
 * SerialOutputString(), but this function just writes the number of
 * characters indicated by bufsize and doesn't look at termination
 * characters.
 */
void ftuart_output_block(const char *buf, int bufsize)
{
	while(bufsize--)
		ftuart_output_byte(*buf++);
}

/*
 * Read a single byte from the serial port. Returns 1 on success, 0
 * otherwise. When the function is succesfull, the character read is
 * written into its argument c.
 */
int ftuart_input_str(char *buf, int count)
{
  int i;

  for(i = 0; i < count; i++)
  {
    while (( __REG(FFUART_BASE_PHYSICAL+FF_LSR_OFFSET) & LSR_DR) == 0)
  	udelay(1);
    buf[i] = __REG(FFUART_BASE_PHYSICAL+FF_RBR_OFFSET) & 0xff;
  }
  return(1);

} /* SerialInputByte */



/*
 * Read a single byte from the serial port. Returns 1 on success, 0
 * otherwise. When the function is succesfull, the character read is
 * written into its argument c.
 */
int ftuart_input_byte(char *c)
{
	int count = 1000;

	while((( __REG(FFUART_BASE_PHYSICAL+FF_LSR_OFFSET) & LSR_DR) == 0)&&(--count>0))
		udelay(1);
	if(count>0)
	{
		*c = __REG(FFUART_BASE_PHYSICAL+FF_RBR_OFFSET) & 0xff;
		return 1;
	}
	else
	{
		*c = 0;
		return 0;
	}
} /* SerialInputByte */


/*
 * read a string with maximum length len from the serial port
 * using a timeout of timeout seconds
 *
 * len is the length of array s _including_ the trailing zero,
 * the function returns the number of bytes read _excluding_
 * the trailing zero
 */
int  ftuart_input_string(char *s, const int len, const int timeout)
{
	u32 startTime, currentTime;
	char c;
	int i;
	int numRead;
	int skipNewline = 1;
	int maxRead = len - 1;

	startTime = TimerGetTime();

	for(numRead = 0, i = 0; numRead < maxRead;) {
		/* try to get a byte from the serial port */
		while(!ftuart_input_byte(&c)) {
			currentTime = TimerGetTime();

			/* check timeout value */
			if((currentTime - startTime) > timeout ) {
				/* timeout */
				s[i++] = '\0';
				return(numRead);
			}
		}
		startTime = TimerGetTime();
		/* eat newline characters at start of string */
		if((skipNewline == 1) && (c != '\r') && (c != '\n'))
			skipNewline = 0;

		if(skipNewline == 0) {
			if((c == '\r') || (c == '\n')) {
				s[i++] = '\0';
				return(numRead);
			} else {
				s[i++] = c;
				numRead++;
			}
		}
	}

	return(numRead);
}


/*
 * SerialInputBlock(): almost the same as SerialInputString(), but
 * this one just reads a block of characters without looking at
 * special characters.
 */
int ftuart_clear_rx(void)
{
    	// Clear the Rx FIFO
	__REG(FFUART_BASE_PHYSICAL+FF_FCR_OFFSET) =FCR_TRFIFOE | FCR_RESETRF ;

	return 0;
}

int  ftuart_input_block(char *buf, int bufsize, const int timeout)
{
    u32 startTime, currentTime;
    char c;
    int i;
    int numRead;
    int maxRead = bufsize;

    startTime = TimerGetTime();

    for(numRead = 0, i = 0; numRead < maxRead;) {
      /* try to get a byte from the serial port */
		while(!ftuart_input_byte(&c)) {
			currentTime = TimerGetTime();

			/* check timeout value */
			if((currentTime - startTime) > timeout) {
				/* timeout! */
				return(numRead);
			}
		}
		startTime = TimerGetTime();
		buf[i++] = c;
		numRead ++;
	}

    return(numRead);
}

void ftuart_input_flush(void)
{
  volatile unsigned int ch;
  while (( __REG(FFUART_BASE_PHYSICAL+FF_LSR_OFFSET) & LSR_DR) != 0) {
    ch = __REG(FFUART_BASE_PHYSICAL+FF_LSR_OFFSET);
  }
  return;
}

